#include <signal.h>
#include <unistd.h>
#include <wait.h>

#include <iostream>

using namespace std;

static int loop = 1;

void signal_process(int SIGNAL) {
  if (SIGNAL == SIGINT) {
    cout << "SIGINT" << endl;
    exit(1);
  } else if (SIGNAL == SIGTERM) {
    cout << "SIGTERM" << endl;
    exit(1);
  } else if (SIGNAL == SIGKILL) {
    cout << "SIGKILL" << endl;
  } else
    cout << "Unknown Signal" << endl;
}

void sigaction_handler(int signo, siginfo_t *info, void *ctx) {
  if (signo == SIGQUIT) {
    loop = 0;
    cout << "QUIT LOOP!" << endl;
    return;
  }
  cout << "Recv From SiQueue :"
       << "si_int [" << info->si_int << "]" << endl
       << "si_value.sival_int [" << info->si_value.sival_int << "]" << endl;
}

int main(int argc, char const *argv[]) {
  // 低级注册信号处理函数
  // signal(SIGTERM, signal_process);
  // signal(SIGKILL, signal_process);
  // signal(SIGQUIT, SIG_IGN);  // 忽略该信号
  // 低级信号发送函数
  // kill(pid, SIGKILL);

  pid_t pid = fork();
  if (pid < 0) {
    perror("Error For Frok()");
    exit(1);
  } else if (pid == 0) {
    cout << "Sub Proc [" << getpid() << "] RUNING" << endl;
    // 高级注册信号函数
    struct sigaction act_int;
    // 指定在处理函数运行期间要屏蔽的信号
    sigemptyset(&act_int.sa_mask);
    // sigaddset(&act_int.sa_mask, SIGQUIT);
    // 打开"接收信号附带消息"开关，默认为NULL
    act_int.sa_flags = SA_SIGINFO;
    // 指定简单的处理函数
    // void (*__sighandler_t) (int 信号值)
    // act_int.sa_handler = SIG_IGN;
    // 指定复杂的处理函数
    // void (*sa_sigaction) (int 信号值, siginfo_t * 信号携带信息, void*
    // 无用参);
    act_int.sa_sigaction = sigaction_handler;
    if (sigaction(SIGINT, &act_int, NULL) < 0) {
      perror("Error for sigaction");
      exit(1);
    }

    struct sigaction act_quit;
    sigemptyset(&act_quit.sa_mask);
    act_quit.sa_flags = 0;
    act_quit.sa_sigaction = sigaction_handler;
    if (sigaction(SIGQUIT, &act_quit, NULL) < 0) {
      perror("Error for sigaction");
      exit(1);
    }

    while (loop)
      ;
    exit(0);
  }

  // 等待进程启动完毕
  sleep(1);

  // 高级信号发送函数
  union sigval sv;
  // 可以传递一个整形（消息类型）
  sv.sival_int = 100;
  if (sigqueue(pid, SIGINT, sv) < 0) {
    perror("Error For sigqueue");
    exit(1);
  }
  kill(pid, SIGQUIT);

  wait(NULL);
  return 0;
}

/**
 * SIGINT终止进程，通常我们的Ctrl+C就发送的这个消息。
 * SIGQUIT和SIGINT类似, 但由QUIT字符(通常是Ctrl- / )来控制.
 *  进程收到该消息退出时会产生core文件。
 * SIGKILL消息编号为9，我们经常用kill
 * -9来杀死进程发送的就是这个消息，程序收到这个消息立即终止，
 *  这个消息不能被捕获，封锁或这忽略，所以是杀死进程的终极武器。
 * SIGTERM是不带参数时kill默认发送的信号，默认是杀死进程。
 * SIGSTOP停止进程的执行，同SIGKILL一样不可以被应用程序所处理，
 *  注意它和terminate以及interrupt的区别:该进程还未结束, 只是暂停执行。
 * SIGCONT当SIGSTOP发送到一个进程时，通常的行为是暂停该进程的当前状态。
 *  如果发送SIGCONT信号，该进程将仅恢复执行。除了其他目的，
 *  SIGSTOP和SIGCONT用于Unix shell中的作业控制，无法捕获或忽略SIGCONT信号。
 * SIGCHLD子进程结束时，父进程会收到这个信号。默认动作为忽略这个信号。
 */
